package com.jcommander.utils;

import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;

import javax.swing.SwingWorker;

import org.apache.commons.io.FileUtils;

public class CopyFileTask extends SwingWorker<Void, Void> {

	// magic number for Windows, 64Mb - 32Kb)
	//because bundle in nio(New Java IO) on Windows can't be above 64MB
    private static final int MAX_COUNT = (64 * 1024 * 1024) - (32 * 1024);
	private final File source;
	private final File destination;
    private final long totalSize;
	private final long bundleSize;
	private int progress = 0;
    
	private List<ActionListener> doneActionListeners = new ArrayList<ActionListener>();
	
	public CopyFileTask(File source, File destination) {
		super();
		this.source = source;
		this.destination = destination;
		if (source.isDirectory()) {
			totalSize = FileUtils.sizeOfDirectory(source);
		} else {
			totalSize = FileUtils.sizeOf(source);
		}
		long size = Math.round(totalSize/100.0f);
		bundleSize = size > MAX_COUNT ? MAX_COUNT : size;
	}
	
	@Override
	public Void doInBackground() throws Exception {
          setProgress(0);
          copyDirectory(source, destination);
          return null;
      }

	 @Override
	public void done() {
		Toolkit.getDefaultToolkit().beep();
		fireDoneAction();
	}
	 
	public void addDoneActionListener(ActionListener listener) {
			doneActionListeners.add(listener);
	}
		
	public void removeDoneActionListener(ActionListener listener) {
		doneActionListeners.remove(listener);
	}
	
	private void fireDoneAction() {
		for (ActionListener l : doneActionListeners) {
			l.actionPerformed(null);
		}
	}
	
	private void copyDirectory(File source , File destination) throws IOException {
		if (source.isDirectory()) {
	        if (!destination.exists()) {
	            destination.mkdir();
	        }
	        
	        String[] children = source.list();
	        for (String child : children) {
	        	 if (progress >= 100 && isCancelled()) {
	        		 break;
	        	 }
	        	 copyDirectory(new File(source, child), new File(destination, child));
			}
	    } else {
	        copyFile(source, destination);
	    }
	}
	
	private void copyFile(File source, File destination) throws IOException {
	 	FileChannel inChannel = new FileInputStream(source).getChannel();
	    FileChannel outChannel = new FileOutputStream(destination).getChannel();
	    try {
	        long position = 0;
	        long inChannelSize = inChannel.size();
	        while (position < inChannelSize) {
				if (progress >= 100 && isCancelled()) {
					 break;
				 }
				position += inChannel.transferTo(position, bundleSize, outChannel);
				progress += 1;
			    setProgress(progress);
	        }
	    }
	    catch (IOException e) {
	        throw e;
	    }
	    finally {
	        if (inChannel != null) inChannel.close();
	        if (outChannel != null) outChannel.close();
	    }
	}
	
	
	
}

/*

/ If targetLocation does not exist, it will be created.
public void copyDirectory(File sourceLocation , File targetLocation) throws IOException {
    
    if (sourceLocation.isDirectory()) {
        if (!targetLocation.exists()) {
            targetLocation.mkdir();
        }
        
        String[] children = sourceLocation.list();
        for (int i=0; i<children.length; i++) {
            copyDirectory(new File(sourceLocation, children[i]),
                    new File(targetLocation, children[i]));
        }
    } else {
        
        InputStream in = new FileInputStream(sourceLocation);
        OutputStream out = new FileOutputStream(targetLocation);
        
        // Copy the bits from instream to outstream
        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        in.close();
        out.close();
    }
}*/
